<?php
//require_once dirname(__FILE__) . "/../../library/alpay/lib/WxPay.Api.php";

/**
 * JSAPI支付实现类
 * 该类实现了从微信公众平台获取code、通过code获取openid和access_token、
 * 生成jsapi支付js接口所需的参数、生成获取共享收货地址所需的参数
 * 该类是微信支付提供的样例程序，商户可根据自己的需求修改，或者使用lib中的api自行开发
 * @author widy
 */
class Jsapipay
{
    /**
     * 网页授权接口微信服务器返回的数据，返回样例如下
     * {
     *  "access_token":"ACCESS_TOKEN",
     *  "expires_in":7200,
     *  "refresh_token":"REFRESH_TOKEN",
     *  "openid":"OPENID",
     *  "scope":"SCOPE",
     *  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     * 其中access_token可用于获取共享收货地址
     * openid是微信支付jsapi支付接口必须的参数
     * @var array
     */
    public $data = null;

    /**
     * 通过跳转获取用户的openid，跳转流程如下：
     * 1、设置自己需要调回的url及其其他参数，跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
     * 2、微信服务处理完成之后会跳转回用户redirect_uri地址，此时会带上一些参数，如：code
     * @return 用户的openid
     */

    public function gettoken($weixin_appid, $weixin_appsecret)
    {
        //access_token 应该全局存储与更新，以下代码以写入到文件中做示例
        $data = json_decode(file_get_contents(\Util\Config::get('weixin_access_token_file', 'Env')));
        if (@$data->expire_time < time()) {
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$weixin_appid&secret=$weixin_appsecret";
            $res = json_decode($this->httpGet($url));
	    $access_token = $res->access_token;
            if ($access_token) {
                $data->expire_time = time() + 7000;
                $data->access_token = $access_token;
            	$fp = fopen(\Util\Config::get('weixin_access_token_file', 'Env'), "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
	    }
        } else {
            $access_token = $data->access_token;
        }
        return $access_token;
    }

    private function httpGet($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_URL, $url);

        $res = curl_exec($curl);
        curl_close($curl);

        return $res;
    }

    public function GetOpenid($config)
    {
        //通过code获得openid
        if (!isset($_GET['code'])) {
            //触发微信返回code码
            $baseUrl = urlencode('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
            $url = $this->__CreateOauthUrlForCode($baseUrl, $config);
            Header("Location: $url");
            exit();
        } else {
            //获取code码，以获取openid
            $code = $_GET['code'];
            $openid = $this->getOpenidFromMp($code, $config);
            if (!$openid) {
                $baseUrl = urlencode('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
                $url = $this->__CreateOauthUrlForCode($baseUrl, $config);
                Header("Location: $url");
                exit();
            }
            return $openid;
        }
    }

    /**
     * 通过code从工作平台获取openid机器access_token
     * @param string $code 微信跳转回来带上的code
     * @return openid
     */
    public function GetOpenidFromMp($code, $config)
    {
        $url = $this->__CreateOauthUrlForOpenid($code, $config);
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, 6);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //运行curl，结果以jason形式返回
        $res = curl_exec($ch);
        curl_close($ch);
        //取出openid
        $data = json_decode($res, true);
        Util\LogUtil::log('wx_get_open_id_res',json_encode($res));

        $this->data = $data;
        $openid = $data['openid'];
        return $openid;
    }

    /**
     * 拼接签名字符串
     * @param array $urlObj
     * @return 返回已经拼接好的字符串
     */
    private function ToUrlParams($urlObj)
    {
        $buff = "";
        foreach ($urlObj as $k => $v) {
            if ($k != "sign") {
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }


    /**
     * 构造获取code的url连接
     * @param string $redirectUrl 微信服务器回跳的url，需要url编码
     * @return 返回构造好的url
     */
    private function __CreateOauthUrlForCode($redirectUrl, $config)
    {
        $urlObj["appid"] = $config['APPID'];
        $urlObj["redirect_uri"] = "$redirectUrl";
        $urlObj["response_type"] = "code";
        $urlObj["scope"] = "snsapi_base";
        $urlObj["state"] = "openid" . "#wechat_redirect";
        $bizString = $this->ToUrlParams($urlObj);
        return "https://open.weixin.qq.com/connect/oauth2/authorize?" . $bizString;
    }

    /**
     * 构造获取open和access_toke的url地址
     * @param string $code ，微信跳转带回的code
     * @return 请求的url
     */
    private function __CreateOauthUrlForOpenid($code, $config)
    {
        $urlObj["appid"] = $config['APPID'];
        $urlObj["secret"] = $config['APPSECRET'];
        $urlObj["code"] = $code;
        $urlObj["grant_type"] = "authorization_code";
        $bizString = $this->ToUrlParams($urlObj);
        return "https://api.weixin.qq.com/sns/oauth2/access_token?" . $bizString;
    }

    /**
     * 获取ticket
     * @param $app_id
     * @param $app_secret
     * @return mixed
     */
    public function wx_get_jsapi_ticket($app_id,$app_secret)
    {
        $data = json_decode(file_get_contents(\Util\Config::get('weixin_ticket_file', 'Env')));
        if (@$data->expire_time < time()) {
            $token = $this->gettoken($app_id,$app_secret);
            $url2 = sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", $token);
            $res = file_get_contents($url2);
            $res = json_decode($res, true);
            if (isset($res['ticket']) == false) {
                Util\LogUtil::log('wx_get_jsapi_ticket_error1',json_encode($res));
                // 重新获取 account_token
                $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$app_id&secret=$app_secret";
                $res = json_decode($this->httpGet($url));
                $access_token = $res->access_token;
                if ($access_token) {
                    $data->expire_time = time() + 7000;
                    $data->access_token = $access_token;
                    file_put_contents(\Util\Config::get('weixin_access_token_file', 'Env'), "w");
                } else {
                    Util\LogUtil::log('wx_get_jsapi_ticket_error2',json_encode($res));
                }
                $url2 = sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", $access_token);
                $res = file_get_contents($url2);
                $res = json_decode($res, true);
                if (isset($res['ticket']) == false) {
                    Util\LogUtil::log('wx_get_jsapi_ticket_error3',json_encode($res));
                }
            } else {
                Util\LogUtil::log('wx_get_jsapi_ticket-ok',json_encode($res));
            }
            $ticket = $res['ticket'];
            if ($ticket) {
                $data->expire_time = time() + 7000;
                $data->ticket = $ticket;
                $fp = fopen(\Util\Config::get('weixin_ticket_file', 'Env'), "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
            }
        } else {
            $ticket = $data->ticket;
        }
        return $ticket;
    }

    /**
     * 获取签名
     * @param $url
     * @param $app_id
     * @param $app_secret
     * @return mixed
     */
    public function getSignature($url,$app_id,$app_secret){
        $timestamp = time();
        $wxnonceStr = "anystring";
        $wxticket = self::wx_get_jsapi_ticket($app_id,$app_secret);
        $wxOri = sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s", $wxticket, $wxnonceStr, $timestamp, $url);
        $wxSha1 = sha1($wxOri);
        $signature['timestamp'] = $timestamp;
        $signature['wxnonceStr'] = $wxnonceStr;
        $signature['wxticket'] = $wxticket;
        $signature['wxSha1'] = $wxSha1;
        return $signature;
    }
}
